.TH std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not 3 "2024.06.10" "http://cppreference.com" "C++ Standard Libary"
.SH NAME
std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not \- std::ranges::find_last,std::ranges::find_last_if,std::ranges::find_last_if_not

.SH Synopsis
 Defined in header <algorithm>
 Call signature
 template< std::forward_iterator I, std::sentinel_for<I> S,

           class T,
           class Proj = std::identity >                                      (since
 requires std::indirect_binary_predicate<ranges::equal_to,                   C++23)
 std::projected<I, Proj>,                                                    (until
                                         const T*>                           C++26)
 constexpr ranges::subrange<I>

     find_last( I first, S last, const T& value, Proj proj = {} );
 template< std::forward_iterator I, std::sentinel_for<I> S,

           class Proj = std::identity,
           class T = std::projected_value_t<I, Proj> >
 requires std::indirect_binary_predicate<ranges::equal_to,                   (since
 std::projected<I, Proj>,                                                    C++26)
                                         const T*>
 constexpr ranges::subrange<I>

     find_last( I first, S last, const T& value, Proj proj = {} );
 template< ranges::forward_range R,

           class T,
           class Proj = std::identity >                                             (since
 requires std::indirect_binary_predicate<ranges::equal_to,                          C++23)
                                                                                    (until
 std::projected<ranges::iterator_t<R>, Proj>,                                       C++26)
                                         const T*>
 constexpr ranges::borrowed_subrange_t<R>

     find_last( R&& r, const T& value, Proj proj = {} );
 template< ranges::forward_range R,

           class Proj = std::identity,
           class T = std::projected_value_t<iterator_t<R>, Proj> >
 requires std::indirect_binary_predicate<ranges::equal_to,                          (since
                                                                                    C++26)
 std::projected<ranges::iterator_t<R>, Proj>,                        \fB(1)\fP
                                         const T*>
 constexpr ranges::borrowed_subrange_t<R>

     find_last( R&& r, const T& value, Proj proj = {} );
 template< std::forward_iterator I, std::sentinel_for<I> S,

           class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>>            \fB(3)\fP    (since
 Pred >                                                                             C++23)
 constexpr ranges::subrange<I>                                           \fB(2)\fP

     find_last_if( I first, S last, Pred pred, Proj proj = {} );
 template< ranges::forward_range R, class Proj = std::identity,


 std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,                (since
 Proj>>                                                                      \fB(4)\fP    C++23)
               Pred >
 constexpr ranges::borrowed_subrange_t<R>

     find_last_if( R&& r, Pred pred, Proj proj = {} );
 template< std::forward_iterator I, std::sentinel_for<I> S,

           class Proj = std::identity,
           std::indirect_unary_predicate<std::projected<I, Proj>>            \fB(5)\fP    (since
 Pred >                                                                             C++23)
 constexpr ranges::subrange<I>

     find_last_if_not( I first, S last, Pred pred, Proj proj = {} );
 template< ranges::forward_range R, class Proj = std::identity,


 std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>,                (since
 Proj>>                                                                      \fB(6)\fP    C++23)
               Pred >
 constexpr ranges::borrowed_subrange_t<R>

     find_last_if_not( R&& r, Pred pred, Proj proj = {} );

   Returns the last element in the range [first, last) that satisfies specific
   criteria:

   1) find_last searches for an element equal to value.
   3) find_last_if searches for the last element in the range [first, last) for which
   predicate pred returns true.
   5) find_last_if_not searches for the last element in the range [first, last) for
   which predicate pred returns false.
   2,4,6) Same as (1,3,5), but uses r as the source range, as if using ranges::begin(r)
   as first and ranges::end(r) as last.

   The function-like entities described on this page are niebloids, that is:

     * Explicit template argument lists cannot be specified when calling any of them.
     * None of them are visible to argument-dependent lookup.
     * When any of them are found by normal unqualified lookup as the name to the left
       of the function-call operator, argument-dependent lookup is inhibited.

   In practice, they may be implemented as function objects, or with special compiler
   extensions.

.SH Parameters

   first, last - the range of elements to examine
   r           - the range of the elements to examine
   value       - value to compare the elements to
   pred        - predicate to apply to the projected elements
   proj        - projection to apply to the elements

.SH Return value

   1,2,3) Let i be the last iterator in the range [first, last) for which E is true.
   Returns ranges::subrange<I>{i, last}, or ranges::subrange<I>{last, last} if no such
   iterator is found.
   2,4,6) Same as (1,2,3) but the return type is ranges::borrowed_subrange_t<I>.

.SH Complexity

   At most last - first applications of the predicate and projection.

.SH Notes

   ranges::find_last, ranges::find_last_if, ranges::find_last_if_not have better
   efficiency on common implementations if I models bidirectional_iterator or (better)
   random_access_iterator.

             Feature-test macro            Value    Std              Feature
                                                          ranges::find_last,
   __cpp_lib_ranges_find_last             202207L (C++23) ranges::find_last_if,
                                                          ranges::find_last_if_not
   __cpp_lib_algorithm_default_value_type 202403  (C++26) List-initialization for
                                                          algorithms (1,2)

.SH Possible implementation

   These implementations only show the slower algorithm used when I models
   forward_iterator.

                                      find_last (1-2)
 struct find_last_fn
 {
     template<std::forward_iterator I, std::sentinel_for<I> S,
              class Proj = std::identity,
              class T = std::projected_value_t<iterator_t<R>, Proj>>
     requires std::indirect_binary_predicate<ranges::equal_to, std::projected<I, Proj>,
                                             const T*>
     constexpr ranges::subrange<I>
         operator()(I first, S last, const T &value, Proj proj = {}) const
     {
         // Note: if I is mere forward_iterator, we may only go from begin to end.
         I found {};
         for (; first != last; ++first)
             if (std::invoke(proj, *first) == value)
                 found = first;

         if (found == I {})
             return {first, first};

         return {found, std::ranges::next(found, last)};
     }

     template<ranges::forward_range R,
              class Proj = std::identity,
              class T = std::projected_value_t<iterator_t<R>, Proj>>
     requires std::indirect_binary_predicate<ranges::equal_to,
                                             std::projected<ranges::iterator_t<R>, Proj>,
                                             const T*>
     constexpr ranges::borrowed_subrange_t<R>
         operator()(R&& r, const T &value, Proj proj = {}) const
     {
         return this->operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
     }
 };

 inline constexpr find_last_fn find_last;
                                    find_last_if (3-4)
 struct find_last_if_fn
 {
     template<std::forward_iterator I, std::sentinel_for<I> S,
              class Proj = std::identity,
              std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
     constexpr ranges::subrange<I>
         operator()(I first, S last, Pred pred, Proj proj = {}) const
     {
         // Note: if I is mere forward_iterator, we may only go from begin to end.
         I found {};
         for (; first != last; ++first)
             if (std::invoke(pred, std::invoke(proj, *first)))
                 found = first;

         if (found == I {})
             return {first, first};

         return {found, std::ranges::next(found, last)};
     }

     template<ranges::forward_range R, class Proj = std::identity,
              std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>>
                  Pred>
     constexpr ranges::borrowed_subrange_t<R>
         operator()(R&& r, Pred pred, Proj proj = {}) const
     {
         return this->operator()(ranges::begin(r), ranges::end(r),
                                 std::ref(pred), std::ref(proj));
     }
 };

 inline constexpr find_last_if_fn find_last_if;
                                  find_last_if_not (5-6)
 struct find_last_if_not_fn
 {
     template<std::forward_iterator I, std::sentinel_for<I> S,
              class Proj = std::identity,
              std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
     constexpr ranges::subrange<I>
         operator()(I first, S last, Pred pred, Proj proj = {}) const
     {
         // Note: if I is mere forward_iterator, we may only go from begin to end.
         I found {};
         for (; first != last; ++first)
             if (!std::invoke(pred, std::invoke(proj, *first)))
                 found = first;

         if (found == I {})
             return {first, first};

         return {found, std::ranges::next(found, last)};
     }

     template<ranges::forward_range R, class Proj = std::identity,
              std::indirect_unary_predicate<std::projected<ranges::iterator_t<R>, Proj>>
                  Pred>
     constexpr ranges::borrowed_subrange_t<R>
         operator()(R&& r, Pred pred, Proj proj = {}) const
     {
         return this->operator()(ranges::begin(r), ranges::end(r),
                                 std::ref(pred), std::ref(proj));
     }
 };

 inline constexpr find_last_if_not_fn find_last_if_not;

.SH Example


// Run this code

 #include <algorithm>
 #include <cassert>
 #include <forward_list>
 #include <iomanip>
 #include <iostream>
 #include <string_view>

 int main()
 {
     namespace ranges = std::ranges;

     constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2};

     {
         constexpr auto i1 = ranges::find_last(v.begin(), v.end(), 3);
         constexpr auto i2 = ranges::find_last(v, 3);
         static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
         static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
     }
     {
         constexpr auto i1 = ranges::find_last(v.begin(), v.end(), -3);
         constexpr auto i2 = ranges::find_last(v, -3);
         static_assert(i1.begin() == v.end());
         static_assert(i2.begin() == v.end());
     }

     auto abs = [](int x) { return x < 0 ? -x : x; };

     {
         auto pred = [](int x) { return x == 3; };
         constexpr auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
         constexpr auto i2 = ranges::find_last_if(v, pred, abs);
         static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
         static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
     }
     {
         auto pred = [](int x) { return x == -3; };
         constexpr auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
         constexpr auto i2 = ranges::find_last_if(v, pred, abs);
         static_assert(i1.begin() == v.end());
         static_assert(i2.begin() == v.end());
     }

     {
         auto pred = [](int x) { return x == 1 or x == 2; };
         constexpr auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
         constexpr auto i2 = ranges::find_last_if_not(v, pred, abs);
         static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
         static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
     }
     {
         auto pred = [](int x) { return x == 1 or x == 2 or x == 3; };
         constexpr auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
         constexpr auto i2 = ranges::find_last_if_not(v, pred, abs);
         static_assert(i1.begin() == v.end());
         static_assert(i2.begin() == v.end());
     }

     using P = std::pair<std::string_view, int>;
     std::forward_list<P> list
     {
         {"one", 1}, {"two", 2}, {"three", 3},
         {"one", 4}, {"two", 5}, {"three", 6},
     };
     auto cmp_one = [](const std::string_view &s) { return s == "one"; };

     // find latest element that satisfy the comparator, and projecting pair::first
     const auto subrange = ranges::find_last_if(list, cmp_one, &P::first);

     // print the found element and the "tail" after it
     for (P const& e : subrange)
         std::cout << '{' << std::quoted(e.first) << ", " << e.second << "} ";
     std::cout << '\\n';

 #if __cpp_lib_algorithm_default_value_type
     const auto i3 = ranges::find_last(list, {"three", 3}); // (2) C++26
 #else
     const auto i3 = ranges::find_last(list, P{"three", 3}); // (2) C++23
 #endif
     assert(i3.begin()->first == "three" && i3.begin()->second == 3);
 }

.SH Output:

 {"one", 4} {"two", 5} {"three", 6}

.SH See also

   ranges::find_end          finds the last sequence of elements in a certain range
   (C++20)                   (niebloid)
   ranges::find
   ranges::find_if
   ranges::find_if_not       finds the first element satisfying specific criteria
   (C++20)                   (niebloid)
   (C++20)
   (C++20)
   ranges::search            searches for a range of elements
   (C++20)                   (niebloid)
   ranges::includes          returns true if one sequence is a subsequence of another
   (C++20)                   (niebloid)
   ranges::binary_search     determines if an element exists in a partially-ordered
   (C++20)                   range
                             (niebloid)
   ranges::contains
   ranges::contains_subrange checks if the range contains the given element or subrange
   (C++23)                   (niebloid)
   (C++23)
